<template>
  <div class="main">

    <!--    </div>-->
    <basic-layout :title="title" :showFilterBtn="false" :showAddBtn="true" @handleAdd="uploadData"
                  @handleFilter="$refs.queryPopupRef.show = true">
      <div class="tubiao">
        <div v-if="dataList.length > 0">
          <div class="mainSaoyiSao" @click="SaomiaoData"/>
          <div class="mainStyleImg" @click="disconData"/>
        </div>
        <div
          v-if="deviceStatus == 1 && dataList.length == 0"
          class="mainStyleUp"
          @click="disconData"
        />
      </div>
            <div class="upStyleBm">
              <p>
               &nbsp;&nbsp;&nbsp; 已经盘点到的物资会展示到下方<span v-if="dataList.length > 0"
              >(总数:{{ dataList.length }})</span
              >
              </p>
            </div>
      <!-- 列表 -->
      <van-row class="listCard">
        <van-pull-refresh
          v-if="dataList.length"
          class="cardVanPullRefresh1"
          v-model="refreshing"
          @refresh="onRefresh"
        >
          <van-list
            v-if="dataList.length > 0"
            v-model="loading"
            :finished="finished"
            finished-text="已经到底啦"
            @load="nextPage"
            :mmediate-check="false"
            :offset="100"
          >
            <van-cell-group
              v-for="(item, i) in dataList"
              :key="i"
              class="dataStyle"
            >
              <van-cell :value="item.SWID"/>
            </van-cell-group>
          </van-list>
        </van-pull-refresh>
        <van-pull-refresh
          v-else
          class="cardVanPullRefresh2"
          v-model="refreshing"
          @refresh="onRefresh"
        >
        </van-pull-refresh>
        <div class="btnBox">
          <van-button  v-if="!looping" type="primary" color="#4eb3e9" size="large" @click="btnStart">开始盘点</van-button>
          <van-button  v-if="looping" type="primary" color="#4eb3e9" size="large" @click="onStopInventory">停止盘点</van-button>
        </div>
      </van-row>
    </basic-layout>


    <van-dialog
      class="dialogMainStyle"
      v-model="showDialog"
      title="请选择设备"
      :show-confirm-button="false"
      :close-on-click-overlay="true"
    >
      <div class="dialogDataStyle">
        <div v-if="devices.length == 0">
          <span>暂无数据</span>
        </div>
        <div
          v-for="item in devices"
          :key="item.deviceId"
          @click="chooseHandle(item)"
        >
          <span>{{ item.deviceId }}</span>
        </div>
      </div>
    </van-dialog>
  </div>
</template>
<script>
var RX_SERVICE_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
var W_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
var R_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
var UHF = 'UHF'
var leftPad = function (value, length, fill) {
  while (length - value.length > 0) {
    value = fill + value
  }
  return value
}
var number2Hex = function (value, byteLength) {
  value = parseInt(value)
  var hex = value.toString(16).toUpperCase()
  byteLength = byteLength || hex.length / 2 + (hex.length % 2)
  return leftPad(hex, byteLength * 2, '0')
}
import { queryPandjg, pandSave } from '@/api/srvAssurance/assetLabel/assetLabel'

export default {
  data () {
    return {
      refreshing: false,
      loading: false,
      finished: false,
      title: '物资盘点',
      dataList: [],
      dataInfo: '',
      dataParam: '',
      queryParam: {
        pdjhid: '',
        pageIndex: 1,
        pageSize: 10,
      },
      showDialog: false,
      looping: false, // 是否正在连续盘点
      enableRssi: false,
      searchVal: '',
      lastRcvData: '',
      devices: [],
      services: [],
      deviceId: '',
      content: '',
      currentDevice: null, // 当前连接的设备
      deviceStatus: 0,
      settingsForm: {},
      scanQRForm: '',
    }
  },
  created () {
    let dataInfo = this.$route.query.dataInfo
    this.dataParam = this.$route.query.param
    if (JSON.stringify(dataInfo) != '"[object Object]"') {
      this.queryParam.pdjhid = dataInfo.ID || ''
      this.dataInfo = dataInfo
      sessionStorage.setItem('areaList-dataInfo', JSON.stringify(dataInfo))
    } else {
      var item = sessionStorage.getItem('areaList-dataInfo')
      var dataParse = JSON.parse(item)
      this.queryParam.pdjhid = dataParse.ID || ''
      this.dataInfo = dataParse
    }
    this.initData()
  },
  mounted () {
    // 监听蓝牙适配器状态变化事件
    wx.onBluetoothAdapterStateChange(function (e) {
      if (!e.available) {
        this.$Notify({
          type: 'warning',
          message: '蓝牙适配器不可用'
        })
      }
    })
  },
  destroy () {
    let deviceId = this.currentDevice.deviceId
    wx.closeBLEConnection({
      deviceId: deviceId,
    })
  },
  methods: {
    onRefresh () {
      setTimeout(() => {
        this.refreshing = false
      }, 1000)
    },
    async initData () {
      this.queryParam.pageIndex = 1
      this.finished = false
      this.loading = true
      await this.getDataList()
      this.refreshing = false
    },
    goBack () {
      this.$router.back()
    },
    // 加载下一页
    nextPage () {
      // 判断第一次查出来的数据是否还有下一页数据，如果没有则不调接口
      if (
        this.dataList.length <
        this.queryParam.pageIndex * this.queryParam.pageSize
      ) {
        this.loading = false
        return
      }
      setTimeout(() => {
        this.queryParam.pageIndex += 1
        this.getDataList()
      }, 1000)
    },
    // 初始化蓝牙模块
    btnStart () {
      let _this = this
      _this.showDialog = true
      _this.isSeach = true
      _this.devices = []
      wx.openBluetoothAdapter({
        success: function (res) {
          console.log('蓝牙模块初始化成功', res)
          wx.startBluetoothDevicesDiscovery({
            allowDuplicatesKey: false,
            success: function (res) {
              console.log('开始搜索', res)
            },
            fail: function (res) {
              this.$toast('开始搜索蓝牙设备失败')
            },
          })
          wx.onBLECharacteristicValueChange(function (res) {
            if (res.value) {
              var value = _this.buffer2Hex(res.value)
              _this.lastRcvData += value
              _this.doRcvData()
            }
          })
          wx.onBluetoothDeviceFound((devices) => {
            if (devices && devices.length > 0) {
              _this.devices = _this.devices.concat(devices)
            }
          })
        },
      })
    },
    // 选中连接
    chooseHandle (item) {
      let _this = this
      this.showDialog = false
      if (this.deviceStatus == 1) {
        _this.$toast('请先断开链接的设备')
        return
      }
      _this.$toast({
        message: '加载中...',
        forbidClick: true
      })
      wx.createBLEConnection({
        deviceId: item.deviceId,
        success: function (res) {
          _this.currentDevice = item
          // 获取蓝牙设备所有 service（服务）
          wx.getBLEDeviceServices({
            deviceId: item.deviceId,
            success: function (res) {
              _this.$toast('连接蓝牙设备成功')
              _this.stop()
              _this.deviceStatus = 1
              _this.services = res.services || []
              _this.enableBleNotify(item)
            },
          })
        },
        fail: function (res) {
          _this.$toast('连接蓝牙设备失败')
        },
      })
    },

    disconData () {
      let _this = this
      let deviceId = this.currentDevice.deviceId
      this.$dialog
        .confirm({
          title: '提示',
          message: '当前链接设备:' + deviceId + '<br>' + '是否断开?',
        })
        .then(() => {
          wx.closeBLEConnection({
            deviceId: deviceId,
            success: function (res) {
              _this.$toast('断开成功')
              _this.deviceStatus = 0
            },
          })
        })
        .catch(() => {
        })
    },

    // 手柄控制按键按下
    onOneStepInventory () {
      if (this.looping) {
        this.onStopInventory()
      } else {
        this.onLoopInventory()
      }
    },
    // 循环盘点
    onLoopInventory: function () {
      if (!this.checkDeviceConnect()) return
      let _this = this
      // 怕万一设备那边没响应，延迟100毫秒发送开始连续盘点指令
      setTimeout(function () {
        _this.sendStartLoopInventoryCmd()
      }, 100)
    },

    // 连续存盘指令发送特殊处理一下
    sendStartLoopInventoryCmd: function () {
      let _this = this
      this.looping = true

      var cmd = this.generateUHFProtocl(0x82, number2Hex(0, 2))
      var buffer = new ArrayBuffer(cmd.length / 2)
      var bufView = new Uint8Array(buffer)

      for (var i = 0; i < cmd.length; i += 2) {
        bufView[i / 2] = parseInt(cmd.substr(i, 2), 16)
      }

      wx.writeBLECharacteristicValue({
        deviceId: _this.currentDevice.deviceId,
        serviceId: RX_SERVICE_UUID,
        characteristicId: W_UUID,
        value: buffer,
        success: function (e) {
          // 连续存盘标签指令发送成功是没有应答的，写入成功之后则直接发送读标签状态指令
          // 每次发送读取标签指令，等待100毫秒
          setTimeout(function () {
            _this.loopReadLabelData()
          }, 100)
        },
        fail: function (e) {
        },
      })
    },

    // 读标签状态
    loopReadLabelData: function () {
      // 如果设备断开，或是停止连续盘点，则不在发送
      if (!this.checkDeviceConnect() || !this.looping) {
        this.sendStopLoopInventoryCmd()
        return
      }

      let _this = this

      var cmd = this.generateUHFProtocl(0xe0)

      var buffer = new ArrayBuffer(cmd.length / 2)
      var bufView = new Uint8Array(buffer)

      for (var i = 0; i < cmd.length; i += 2) {
        bufView[i / 2] = parseInt(cmd.substr(i, 2), 16)
      }

      wx.writeBLECharacteristicValue({
        deviceId: _this.currentDevice.deviceId,
        serviceId: RX_SERVICE_UUID,
        characteristicId: W_UUID,
        value: buffer,
        success: function (e) {
        },
        failed: function (e) {
        },
        complete: function (e) {
          // 不管成功或者失败，只要还在连续盘点标签，则一直发
          setTimeout(function () {
            _this.loopReadLabelData()
          }, 10)
        },
      })
    },

    // 解析连续盘点读到标签数据
    parseLoopInventoryData: function (data) {
      this.parseLoopInventoryDataWithNoRssi(data)
    },

    // 解析连续盘点读到标签数据（不带RSSI）
    parseLoopInventoryDataWithNoRssi: function (data) {
      var labelCount = parseInt(data.substr(4, 2), 16)
      data = data.substr(6)

      for (var i = 0; i < labelCount; i++) {
        var labelLength = parseInt(data.substr(0, 2), 16)
        var labelEpc = data.substr(2, labelLength * 2)
        data = data.substr(2 + labelLength * 2)
        this.createInventoryRecord({
          epc: labelEpc,
          rssi: '',
        })
      }
    },
    // 创建一条盘点记录
    createInventoryRecord: function (record) {
      let _this = this
      if (record.epc != '') {
        for (let index = 0; index < _this.dataList.length; index++) {
          const element = _this.dataList[index].SWID
          if (element == record.epc) {
            return
          }
        }
        _this.dataList.push({
          SWID: record.epc,
        })
      }
    },
    //扫描盘点
    SaomiaoData: function () {
      if (!this.checkDeviceConnect()) return
      var cmd = this.generateUHFProtocl(0xE4, '02')
      this.sendData(cmd)
    },
    // 处理接收到的报文
    doRcvData: function () {
      while (true) {
        var startIndex = this.lastRcvData.indexOf('C88C')
        var startIndex2 = this.lastRcvData.indexOf('A55A')
        var endIndex = this.lastRcvData.indexOf('0D0A', startIndex + 1)
        if (startIndex < 0) startIndex = startIndex2
        // this.showToast(this.lastRcvData + " ", 2000)
        // this.showToast(startIndex + " " + endIndex, 2000)
        // 错误报文，没有找到消息头
        if (startIndex < 0) break
        // 不完整的报文
        if (endIndex < 0) break
        // 截取C88C开头和ODOA结尾的报文
        var data = this.lastRcvData.substr(startIndex, endIndex - startIndex + 4)
        // 报文至少都有8字节，小于8字节的则为无效报文, 截取掉无效的部分
        if (data.length < 16) {
          this.lastRcvData = this.lastRcvData.substr(startIndex + 4)
          continue
        }
        // 检查报文长度
        var length = parseInt(data.substr(4, 4), 16)
        // 如果报文长度不对，则是错误报文, 截取掉无效的部分
        if (length * 2 != data.length) {
          this.lastRcvData = this.lastRcvData.substr(startIndex + 4)
          continue
        }
        // 获取内容部分, 用于下一步做校验和验证
        var content = data.substr(4, data.length - 10)
        var checkSum = this.calcCheckSum(content)
        // 校验和结果不正确, 截取掉无效的部分
        if (checkSum != parseInt(data.substr(data.length - 6, 2), 16)) {
          this.lastRcvData = this.lastRcvData.substr(startIndex + 4)
          continue
        }
        var protocol = this.createProtocol(data)
        if (protocol) {
          switch (protocol.type) {
            case UHF:
              this.parseUHFProtocol(protocol.payload)
              break
          }
        }
        // 截取已处理的字符串, 进入到下一步处理
        this.lastRcvData = this.lastRcvData.substr(endIndex + 4)
      }
    },

    // 解析UHF协议对象
    parseUHFProtocol: function (payload) {
      var success = 1
      var ctrlCode = 0

      function hex2Str (hex) {
        var result = ''
        for (var i = 0; i < hex.length; i += 2) {
          var code = String.fromCharCode(parseInt(hex.substr(i, 2), 16))
          result += code
        }
        return result
      }

      switch (payload.cmdId) {
        case 0x2f:
          success = parseInt(payload.data.substr(0, 2), 16)
          this.settingsForm.frequency = parseInt(payload.data.substr(2, 2), 16)
          break
        case 0x13:
          this.settingsForm.power =
            parseInt(payload.data.substr(4, 4), 16) / 100
          break
        case 0x85:
          success = parseInt(payload.data.substr(0, 2), 16)
          this.readLabelForm.data = payload.data.substr(8)
          break
        case 0x71:
          success = parseInt(payload.data.substr(0, 2), 16)
          break
        case 0xe5:
          // 由于开关蜂鸣器和二维码扫描的回复都是0xE5，无法区分。这里只能通过当前标签卡的id来判断是哪条指令的回调
          ctrlCode = parseInt(payload.data.substr(0, 2), 16)
          this.dataList.push({
            SWID: hex2Str(payload.data.substr(2))
          })
          break
        case 0x81:
          this.parseInventoryData(payload.data)
          return
        case 0xe1:
          this.parseLoopInventoryData(payload.data)
          return
        case 0x6f:
          success = parseInt(payload.data.substr(0, 2), 16)
          break
        case 0xe6:
          this.onOneStepInventory()
          return
        case 0x03:
          // 获取UHF版本
          utils.alert(
            'UHF版本:v' +
            parseInt(payload.data.substr(0, 2), 16) +
            '.' +
            parseInt(payload.data.substr(2, 2), 16) +
            '.' +
            parseInt(payload.data.substr(4, 2), 16)
          )
          return
      }

      // this.outputUHFLog(payload, success);
    },
    // 单次盘点读取到标签数据
    parseInventoryData: function (payload) {
      var pc = payload.substr(0, 4)
      var length = parseInt(pc, 16) >>> 10
      if (length == 0) return
      var epc = payload.substr(4, length * 2)
      var rssi = payload.substr(payload.length - 6, 4)

      // 计算补码 / 10
      rssi = parseInt(rssi, 16)
      if ((rssi & 0x8000) == 0x8000) {
        rssi = (~rssi & 0xffff) * -1 - 1
      }
      rssi /= 10

      var record = {
        epc: epc,
        rssi: rssi,
      }
      let _this = this
      for (let index = 0; index < _this.dataList.length; index++) {
        const element = _this.dataList[index].SWID
        if (element == record.epc) {
          _this.$dialog
            .alert({
              message: element + '<br>' + '重复扫码',
            })
            .then(() => {
            })
          return
        }
      }
      _this.dataList.push({
        SWID: record.epc,
      })
    },

    // 根据完整的报文生成protocol对象
    createProtocol: function (hex) {
      var cmdId = parseInt(hex.substr(8, 2), 16)
      var data = hex.substr(10, hex.length - 16)

      // 解析出的对象只包含命令字和内容
      var protocol = {
        type: UHF,
        payload: {
          cmdId: cmdId,
          data: data,
        },
      }
      return protocol
    },

    buffer2Hex: function (value) {
      var t = ''
      if (value) {
        var v = new Uint8Array(value)
        for (var i in v) {
          var hex = v[i].toString(16).toUpperCase()
          if (hex.length == 1) {
            t += '0'
          }

          t += hex
        }
      }
      return t
    },

    enableBleNotify (device) {
      // 这里监听时,ios测试需要有点延迟,安卓的话,只在测试机上测试过,不需要延迟
      setTimeout(function () {
        wx.notifyBLECharacteristicValueChange({
          state: true, // 启用 notify 功能
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
          deviceId: device.deviceId,
          // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
          serviceId: RX_SERVICE_UUID,
          // 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
          characteristicId: R_UUID,
          success: function (res) {
            console.log('链接成功，获取服务', res)
          },
          fail: function (res) {
            console.log('链接失败，请重试', res)
          },
        })
      }, 1000)
    },

    calcCheckSum (content) {
      var checkSum = 0
      for (var i = 0; i < content.length; i += 2) {
        var value = parseInt(content.substr(i, 2), 16)
        checkSum ^= value
      }
      return checkSum
    },

    sendData (hexStr, serviceId, characteristicId) {
      if (hexStr == null) return
      serviceId = serviceId || RX_SERVICE_UUID
      characteristicId = characteristicId || W_UUID
      var self = this
      var sendData
      // ble发送数据时，需要分包，最多20字节
      if (hexStr.length > 40) {
        sendData = hexStr.substr(0, 40)
        hexStr = hexStr.substr(40, hexStr.length - 40)
      } else {
        sendData = hexStr
        hexStr = null
      }
      var buffer = new ArrayBuffer(sendData.length / 2)
      var bufView = new Uint8Array(buffer)
      for (var i = 0; i < sendData.length; i += 2) {
        bufView[i / 2] = parseInt(sendData.substr(i, 2), 16)
      }
      wx.writeBLECharacteristicValue({
        deviceId: self.currentDevice.deviceId,
        serviceId: serviceId,
        characteristicId: characteristicId,
        value: buffer,
        success: function (e) {
          // 由于写字节限制，如果还有未发送完的数据，接着继续发送
          self.sendData(hexStr)
        },
        fail: function (e) {
        },
      })
    },
    generateUHFProtocl (cmdId, data) {
      data = data || ''
      // 按理说data长度肯定是2的整数倍
      if (data.length % 2 == 1) {
        data += '0'
      }
      var header = 'C88C'
      var length = number2Hex(8 + data.length / 2, 2)
      var content = length + number2Hex(cmdId, 1) + data
      var checkSum = this.calcCheckSum(content)
      var tail = '0D0A'
      return header + content + number2Hex(checkSum, 1) + tail
    },
    // 停止读标签状态
    stopReadLabelData: function () {
      this.looping = false
      this.$toast('已停止盘点')
    },
    // 发送停止连续盘点标签
    sendStopLoopInventoryCmd: function () {
      this.stopReadLabelData()
      if (!this.checkDeviceConnect()) return
      var cmd = this.generateUHFProtocl(0x8c)
      this.sendData(cmd)
    },
    // 停止盘点
    onStopInventory: function () {
      this.sendStopLoopInventoryCmd()
    },
    stop () {
      let _this = this
      // 停止搜寻附近的蓝牙外围设备
      wx.stopBluetoothDevicesDiscovery({
        success: function (res) {
          console.log('断开搜索')
          _this.isSeach = false
        },
      })
    },
    // 检查设备链接状态
    checkDeviceConnect: function () {
      if (!this.currentDevice) {
        this.$toast('没有设备连接')
        return false
      }
      return true
    },
    // ----------------------------------------------------
    async getDataList () {
      this.loading = true
      let res = await queryPandjg(this.queryParam)
      if (res.status == 0) {
        if (this.queryParam.pageIndex == 1) {
          // 清空列表数据
          this.dataList = []
        }
        this.dataList = this.dataList.concat(res.data)
        // 如果数据加载完毕，finished 标志位置为 true，滑到页面底部则不会再触发 nextPage() 方法了。
        if (this.dataList.length >= res.totalCount) {
          this.finished = true
        }
      }
      this.loading = false
    },
    async uploadData () {
      let arr = []
      this.dataList.forEach((item) => {
        arr.push(item.SWID)
      })
      let dataParam = {
        pdjhid: this.dataInfo.ID,
        swid: arr.toString(),
        lyxxid: this.dataParam.LYXXID,
        lcxxid: this.dataParam.LCXXID,
        fjxxid: this.dataParam.FJXXID,
      }
      let res = await pandSave(dataParam)
      if (res.status == 0) {
        this.$toast.success('盘点计划保存成功')
        this.getDataList()
      }
    },
  },

}
</script>
<style scoped lang="less">
.main {
  .tubiao {
    .mainUpStyleImg {
      width: 30px;
      height: 30px;
      top: 1.3%;
      right: 4%;
      background: url("../../../assets/images/nx/icon_upload.png") no-repeat;
      background-size: 100% 100%;
    }

    .mainSaoyiSao {
      position: absolute;
      width: 26px;
      height: 26px;
      top: 1.4%;
      right: 22%;
      z-index: 1;
      background: url('../../../assets/images/nx/saoyisao.png') no-repeat;
      background-size: 88% 88%
    }

    .mainStyleImg {
      width: 26px;
      height: 26px;
      position: absolute;
      top: 1.7%;
      right: 11%;
      z-index: 1;
      background: url("../../../assets/images/nx/断开.png") no-repeat;
      background-size: 68% 68%;
    }

    .mainStyleUp {
      position: absolute;
      width: 26px;
      height: 26px;
      top: 1.7%;
      right: 11%;
      z-index: 1;
      background: url("../../../assets/images/nx/断开.png") no-repeat;
      background-size: 68% 68%;
    }

    .mid {
      height: 1px;
      color: #ffffff;
      background-color: #ffffff;
    }

    .mainUpStyleImgGoBack {
      width: 25px;
      height: 20px;
      position: absolute;
      top: 0.3rem;
      left: 5%;
      background: url("../../../assets/images/nx/icon_top_back.png") no-repeat;
      background-size: 100% 100%;
    }


    .upStyleBm {
      margin-left: 20px;
      color: #ffffff;
    }
  }

  .listCard {
    margin-top: 5px;
    height: 100%;
    background-color: #80808024;

    .cardVanPullRefresh1 {
      min-height: 10%;
    }
  }
  .btnBox {
    position: absolute;
    //bottom: 0px;
    width: 100%;
    text-align: center;
  }
  .cardVanPullRefresh2 {
    height: 10%;

    .dataStyle {
      height: 162px;
      margin: 15px 10px;
      background-color: #ffffff;
      border-radius: 10px;
    }

    .custom-image {
      height: 100%;
    }
  }

  .dialogMainStyle {
    .dialogSearchStyle {
      position: fixed;
      width: 100%;
    }

    .dialogDataStyle {
      text-align: center;
      // margin-top: 50px;

      div {
        padding: 10px;
      }
    }
  }

  /deep/ .van-dialog {
    height: 70%;
  }

  /deep/ .van-dialog__header {
    padding-top: 20px;
    padding-bottom: 8px;
  }

  /deep/ .van-dialog__content {
    overflow-y: scroll;
    height: 90%;
  }
}
.btnBox /deep/ .van-button--large {
}

.van-button--large {
  height: 40px;
  line-height: 40px;
  width: 95%;
  margin: 10px auto;
}
</style>
